//
//  x86.h
//

void outportw(unsigned short port, int word);
unsigned short inportw(int port);
void outportl(int port, unsigned long value);
unsigned long inportl(int port);

static inline void outportb(unsigned short port, unsigned val)
{
   __asm__ __volatile__("outb %%al,%%dx"::"a"(val),"d"(port));
}

static inline unsigned char inportb(unsigned short port)
{
   unsigned char ret;
   __asm__ __volatile__("inb %%dx,%%al":"=a"(ret):"d"(port));
   return ret;
}

// Definitions
#define PAGEPRESENT_BIT   0x00000001
#define WRITABLE_BIT      0x00000002
#define USER_BIT          0x00000004
#define WRITETHROUGH_BIT  0x00000008
#define CACHEDISABLE_BIT  0x00000010
#define GLOBAL_BIT        0x00000100

#define sti() __asm__ __volatile__("sti":::"memory")
#define cli() __asm__ __volatile__("cli":::"memory")

#define outb(val,port) outportb(port,val)
#define inb(port) inportb(port)

#define ProcStop()                 \
  __asm__ __volatile__ ("cli \n\t" \
                        "hlt")

#define ProcReboot()                            \
  __asm__ __volatile__ ("cli \n\t"              \
                        "movl $0xFE, %eax \n\t" \
                        "outb %al, $0x64 \n\t"  \
                        "hlt")

#define ProcCopyDwords(src, dest, count)            \
  __asm__ __volatile__ ("pushal \n\t"               \
                        "pushfl \n\t"               \
                        "cld \n\t"                  \
                        "rep movsl \n\t"            \
                        "popfl \n\t"                \
                        "popal"                     \
                        : : "S" (src), "D" (dest), "c" (count))

#define ProcCopyBytes(src, dest, count)            \
  __asm__ __volatile__ ("pushal \n\t"              \
                        "pushfl \n\t"              \
                        "cld \n\t"                 \
                        "rep movsb \n\t"           \
                        "popfl \n\t"               \
                        "popal"                    \
                        : : "S" (src), "D" (dest), "c" (count))

#define ProcWriteDwords(value, dest, count)            \
  __asm__ __volatile__ ("pushal \n\t"                  \
                        "pushfl \n\t"                  \
                        "cld \n\t"                     \
                        "rep stosl \n\t"               \
                        "popfl \n\t"                   \
                        "popal"                        \
                        : : "a" (value), "D" (dest), "c" (count))

#define ProcWriteBytes(value, dest, count)            \
  __asm__ __volatile__ ("pushal \n\t"                 \
                        "pushfl \n\t"                 \
                        "cld \n\t"                    \
                        "rep stosb \n\t"              \
                        "popfl \n\t"                  \
                        "popal"                       \
                        : : "a" (value), "D" (dest), "c" (count))

#define ProcFarCall(selector)                 \
  __asm__ __volatile__ ("pushfl \n\t"         \
                        "pushl %%eax \n\t"    \
                        "pushl $0 \n\t"       \
                        "lcall *(%%esp) \n\t" \
                        "addl $8, %%esp \n\t" \
                        "popfl"               \
                        : : "a" (selector));

#define ProcSetGDT(ptr, size)                 \
  __asm__ __volatile__ ("pushfl \n\t"         \
                        "cli \n\t"            \
                        "pushl %0 \n\t"       \
                        "pushw %%ax \n\t"     \
                        "lgdt (%%esp) \n\t"   \
                        "addl $6, %%esp \n\t" \
                        "popfl"               \
                        : : "r" (ptr), "a" (size));

#define ProcSetIDT(ptr, size)                 \
  __asm__ __volatile__ ("pushfl \n\t"         \
                        "cli \n\t"            \
                        "pushl %0 \n\t"       \
                        "pushw %%ax \n\t"     \
                        "lidt (%%esp) \n\t"   \
                        "addl $6, %%esp \n\t" \
                        "popfl"               \
                        : : "r" (ptr), "a" (size));

#define ProcClearAddressCache(address) \
  __asm__ __volatile__ ("invlpg %0"    \
                        : : "m" (*((char *) address)))

#define ProcGetCR3(variable)             \
  __asm__ __volatile__ ("movl %%cr3, %0" \
                        : "=r" (variable))

#define ProcSetCR3(variable)             \
  __asm__ __volatile__ ("movl %0, %%cr3" \
                        : : "r" (variable))

#define ProcGetESP(variable)             \
  __asm__ __volatile__ ("movl %%esp, %0" \
                        : "=r" (variable))

#define ProcIntReturn() __asm__ __volatile__ ("iret")

#define ProcLoadTaskReg(selector)       \
  __asm__ __volatile__ ("pushfl \n\t"   \
                        "cli \n\t"      \
                        "ltr %%ax \n\t" \
                        "popfl"         \
                        : : "a" (selector))

#define ProcInPort8(port, data)          \
  __asm__ __volatile__ ("inb %%dx, %%al" \
                        : "=a" (data) : "d" (port))

#define ProcOutPort8(port, data)          \
  __asm__ __volatile__ ("outb %%al, %%dx" \
                        : : "a" (data), "d" (port))

#define ProcInPort16(port, data)         \
  __asm__ __volatile__ ("inw %%dx, %%ax" \
                        : "=a" (data) : "d" (port))

#define ProcOutPort16(port, data)         \
  __asm__ __volatile__ ("outw %%ax, %%dx" \
                        : : "a" (data), "d" (port))

#define ProcRepInPort16(port, buffer, reads) \
  __asm__ __volatile__ ("pushal \n\t"        \
                        "pushfl \n\t"        \
                        "cli \n\t"           \
                        "cld \n\t"           \
                        "rep insw \n\t"      \
                        "popfl \n\t"         \
                        "popal"              \
                        : : "d" (port), "D" (buffer), "c" (reads))

#define ProcRepOutPort16(port, buffer, writes) \
  __asm__ __volatile__ ("pushal \n\t"          \
                        "pushfl \n\t"          \
                        "cli \n\t"             \
                        "cld \n\t"             \
                        "rep outsw \n\t"       \
                        "popfl \n\t"           \
                        "popal"                \
                        : : "d" (port), "S" (buffer), "c" (writes))

#define ProcIntStatus(variable)           \
  __asm__ __volatile__ ("pushfl \n\t"     \
                        "popl %0 \n\t"    \
                        "shr $9, %0 \n\t" \
                        "and $1, %0"      \
                        : "=r" (variable))

#define ProcEnableInts() __asm__ __volatile__ ("sti")

#define ProcDisableInts() __asm__ __volatile__ ("cli")

#define ProcSuspendInts(variable) \
{                                 \
  ProcIntStatus(variable);        \
  ProcDisableInts();              \
}

#define ProcRestoreInts(variable) \
{                                 \
  if (variable)                   \
    ProcEnableInts();             \
}

#define ProcIsrEnter()                         \
  __asm__ __volatile__ ("cli \n\t"             \
                        "movl %ebp, %esp \n\t" \
                        "pushal")

#define ProcIsrExit()                          \
  __asm__ __volatile__ ("movl %ebp, %esp \n\t" \
                        "subl $32, %esp \n\t"  \
                        "popal \n\t"           \
                        "popl %ebp \n\t"       \
                        "iret")

#define ProcApiEnter()                         \
  __asm__ __volatile__ ("movl %ebp, %esp \n\t" \
                        "pushal")

#define ProcApiExit(code)                        \
  __asm__ __volatile__ ("movl %%ebp, %%esp \n\t" \
                        "subl $32, %%esp \n\t"   \
                        "popal \n\t"             \
                        "popl %%ebp \n\t"        \
                        "movl %0, %%eax \n\t"    \
                        "lret" : : "m" (code));

#define ProcDelay()                            \
  __asm__ __volatile__ ("pushal \n\t"          \
                        "mov $0x3F6, %dx \n\t" \
                        "inb %dx, %al \n\t"    \
                        "inb %dx, %al \n\t"    \
                        "inb %dx, %al \n\t"    \
                        "inb %dx, %al \n\t"    \
                        "popal")
